/*
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package botobjects;

import interfaces.BotObject;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import main.Bot;
import main.CommonMethods;
import main.Constants;

import org.apache.log4j.Logger;
import org.jibble.pircbot.Colors;

import timers.ArmyTimer;
import tools.StringTools;
import tools.UtopiaTime;
import database.DBConnectionFactory;

/**
 * This class represents and army
 * 
 * 
 */
public class Army implements BotObject {
   public static boolean deleteFromDB(final String... args) {
	  boolean out = false;
	  int armyno = 0;
	  try {
		 armyno = Integer.parseInt(args[1]);
	  } catch (NumberFormatException e) {
		 Logger.getLogger("Error").error("", e);
		 return out;
	  }
	  if (args.length < 2 || armyno < 1)
		 return out;
	  PreparedStatement ps = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM army WHERE mainnick = ? AND armyno = ?");

		 ps.setString(1, args[0]);
		 ps.setInt(2, armyno);
		 if (ps.executeUpdate() == 1) {
			Bot.getInstance().getTimerHandler().removeArmyTimer(args[0], armyno);
			out = true;
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   /**
    * Returns a list of armies
    * 
    * @param searchType
    *           Decides what armies to look for. A single user's armies, or a kd's armies etc.
    * @param args
    *           The info needed to specify which armies to look for (might not be needed)
    * @return a List of Army objects
    */
   public static List<Army> getArmies(final int searchType, final Object... args) {
	  List<Army> out = new LinkedList<Army>();
	  for (Object o : args) {
		 if (o == null)
			return out;
	  }
	  PreparedStatement ps = null;
	  ResultSet rs = null;
	  try {
		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("DELETE FROM somarmy WHERE returntime < ?");
		 ps.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
		 ps.executeUpdate();

		 try {
			ps.close();
		 } catch (final Exception e) {
		 }

		 if (searchType == Constants.ARMY_GET_SINGLE_USER && args.length == 1) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM army WHERE mainnick = ?");
			ps.setString(1, (String) args[0]);
		 } else if (searchType == Constants.ARMY_GET_ALL_INTRA) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM army ORDER BY armyhome ASC");
		 } else if (searchType == Constants.ARMY_GET_ALL_KD && args.length == 1) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement(
						"SELECT * FROM somarmy,province WHERE province.name = "
							  + "somarmy.name AND kdloc = ? ORDER BY returntime ASC");
			ps.setString(1, (String) args[0]);
		 } else if (searchType == Constants.ARMY_GET_NUMBER_LIMITED_INTRA && args.length == 1) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM army ORDER BY armyhome ASC LIMIT ?");
			ps.setInt(1, (Integer) args[0]);
		 } else if (searchType == Constants.ARMY_GET_NUMBER_LIMITED_KD && args.length == 2) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement(
						"SELECT * FROM somarmy,province WHERE kdloc = ? AND province.name = somarmy.name ORDER BY "
							  + "returntime ASC LIMIT ?");
			ps.setString(1, (String) args[0]);
			ps.setInt(2, (Integer) args[1]);
		 } else if (searchType == Constants.ARMY_GET_TIME_LIMITED_INTRA && args.length == 1) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM army WHERE armyhome < ? ORDER BY armyhome ASC");
			ps.setTimestamp(1, new Timestamp(Calendar.getInstance().getTimeInMillis() + ((Date) args[0]).getTime()));
		 } else if (searchType == Constants.ARMY_GET_TIME_LIMITED_KD && args.length == 2) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement(
						"SELECT * FROM somarmy,province WHERE province.name = "
							  + "somarmy.name AND kdloc = ? AND returntime < ? ORDER BY returntime ASC");
			ps.setString(1, (String) args[0]);
			ps.setTimestamp(2, new Timestamp(Calendar.getInstance().getTimeInMillis() + ((Date) args[0]).getTime()));
		 } else if (searchType == Constants.ARMY_GET_RETURNING_THIS_TICK) {
			ps = DBConnectionFactory.getConnectionHandler().getConnection()
				  .prepareStatement("SELECT * FROM army WHERE armyhome < ?");
			ps.setTimestamp(1, new Timestamp(((Date) args[0]).getTime() + 3600000 - 1));
		 } else if (searchType == Constants.ARMY_GET_ALL_HOME) {
			ps = DBConnectionFactory
				  .getConnectionHandler()
				  .getConnection()
				  .prepareStatement(
						"SELECT * FROM kdprovince WHERE NOT EXISTS (SELECT * FROM army WHERE "
							  + "kdprovince.mainnick = army.mainnick)");
		 }
		 if (ps != null) {
			rs = ps.executeQuery();

			while (rs.next()) {
			   if (searchType == Constants.ARMY_GET_ALL_KD || searchType == Constants.ARMY_GET_NUMBER_LIMITED_KD
					 || searchType == Constants.ARMY_GET_TIME_LIMITED_KD) {
				  out.add(new Army(rs.getString("name"), rs.getInt("armyno"), rs.getTimestamp("returntime").getTime(), 0L, 0, rs
						.getInt("generals"), "0"));
			   } else if (searchType == Constants.ARMY_GET_ALL_HOME) {
				  out.add(new Army(rs.getString("mainnick"), 0, 0L, 0L, 0, 0, ""));
			   } else {
				  out.add(new Army(rs.getString("mainnick"), rs.getInt("armyno"), rs.getTimestamp("armyhome").getTime(), rs
						.getTimestamp("armyadded").getTime(), rs.getInt("mo"), rs.getInt("generals"), rs.getString("gain")));
			   }
			}
		 }
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			rs.close();
		 } catch (final Exception e) {
		 }
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }

   private String nick = "";
   private Integer army = 0;
   private Long hometime = 0L;
   private Long timeofattack = 0L;
   private Integer mo = 0;

   private Integer generals = 0;

   private String gain = "";

   public Army(final String nick, final Integer army, final Long hometime, final Long timeofattack, final int mo,
		 final int generals, final String gain) {
	  this.nick = nick;
	  this.army = army;
	  this.hometime = hometime;
	  this.timeofattack = timeofattack;
	  this.mo = mo;
	  this.generals = generals;
	  this.gain = gain;
   }

   public Long getArmyHome() {
	  return hometime;
   }

   public Integer getArmyNo() {
	  return army;
   }

   public String getGain() {
	  return gain;
   }

   public Integer getGenerals() {
	  return generals;
   }

   @Override
   public List<String> getIRCOutput(final int outputType, final String... args) {
	  List<String> out = new LinkedList<String>();
	  if (StringTools.isNullOrEmpty(getMainNick()) || getArmyNo() == null || getArmyHome() == null || getTimeofattack() == null
			|| getMO() == null || getGenerals() == null || getGain() == null)
		 return out;
	  if (outputType == Constants.ARMY_REGULAR_OUTPUT) {
		 String output = " returns in " + Colors.BLUE + UtopiaTime.compareTimes(getArmyHome());

		 out.add(Colors.RED + getMainNick() + Colors.TEAL + " Army " + getArmyNo() + Colors.OLIVE + output + Colors.NORMAL
			   + (getMO() != 0 ? " (" + getMO() + " mo)" : "") + (!getGain().equals("0") ? " (" + getGain() + ")" : "")
			   + (getGenerals() != 0 ? " (" + getGenerals() + " gens)" : ""));
	  } else if (outputType == Constants.ARMY_LOCAL_TIME_OUTPUT && args.length == 1) {
		 String pattern = "EEE, MMM d, H:mm:ss";
		 SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US);
		 sdf.setTimeZone(TimeZone.getTimeZone("GMT" + CommonMethods.getUserTimeZone(args[0])));
		 String out1 = sdf.format(new java.util.Date(getArmyHome()));
		 String temp = " returns " + Colors.BLUE + out1;

		 out.add(Colors.RED + nick + Colors.TEAL + " Army " + getArmyNo() + Colors.OLIVE + temp);
	  }

	  return out;
   }

   public String getMainNick() {
	  return nick;
   }

   public Integer getMO() {
	  return mo;
   }

   @Override
   public Map<String, Object> getRPCOutput(final int... includes) {
	  Map<String, Object> out = new HashMap<String, Object>();
	  if (StringTools.isNullOrEmpty(getMainNick()) || getArmyNo() == null || getArmyHome() == null || getTimeofattack() == null
			|| getMO() == null || getGenerals() == null || getGain() == null)
		 return out;
	  out.put("Nick", getMainNick());
	  out.put("Army Number", getArmyNo());
	  out.put("Time of Return", new Date(getArmyHome()));
	  out.put("Time of Attack", new Date(getTimeofattack()));
	  out.put("Gain", getGain());
	  out.put("Generals", getGenerals());
	  out.put("Mod Off", getMO());
	  return out;
   }

   public Long getTimeofattack() {
	  return timeofattack;
   }

   @Override
   public boolean saveToDB() {
	  boolean out = false;
	  if (StringTools.isNullOrEmpty(getMainNick()) || getArmyNo() == null || getArmyHome() == null || getTimeofattack() == null
			|| getMO() == null || getGenerals() == null || getGain() == null)
		 return out;
	  PreparedStatement ps = null;
	  try {
		 deleteFromDB(getMainNick(), String.valueOf(getArmyNo()));

		 ps = DBConnectionFactory.getConnectionHandler().getConnection()
			   .prepareStatement("INSERT INTO army VALUES(?,?,?,?,?,?,?)");
		 ps.setInt(1, getArmyNo());
		 ps.setTimestamp(2, new Timestamp(getArmyHome()));
		 ps.setString(3, getMainNick());
		 ps.setInt(4, getMO());
		 ps.setString(5, getGain());
		 ps.setTimestamp(6, new Timestamp(getTimeofattack()));
		 ps.setInt(7, getGenerals());
		 if (ps.executeUpdate() == 1) {
			out = true;
		 }

		 Bot.getInstance().getTimerHandler().removeArmyTimer(getMainNick(), getArmyNo());
		 Bot.getInstance().getTimerHandler()
			   .addArmyTimer(new ArmyTimer(getMainNick(), getArmyNo(), getArmyHome() - Calendar.getInstance().getTimeInMillis()));
	  } catch (final SQLException e) {
		 Logger.getLogger("Error").error("", e);
	  } finally {
		 try {
			ps.close();
		 } catch (final Exception e) {
		 }
	  }
	  return out;
   }
}
